using System;
using System.Collections.Generic;
using System.Text;

namespace Scheduler
{
    /*
     * An object of this class holds the daily schedule for one day only
     * The information held by this object are:
     * the name of the day, eg.Friday, (String day)
     * 24 scheduling slots starting from 8 am and ending at 8 pm in 
     * chunks of 30 minutes( 12*2 = 24) each called a 
     * schedSlot(private SchedSlot[] daySchedule)
     */
    public class DailySched
    {
        private String day;
        private SchedSlot[] daySchedule;
        private int scheduleID;

        public DailySched()
        {
            day = "";
            daySchedule = new SchedSlot[24];
            for (int i = 0; i < daySchedule.Length; i++)
            {
                daySchedule[i] = new SchedSlot();
            }
        }

        public DailySched(String dayName)
        {
            day = dayName;
            daySchedule = new SchedSlot[24];
            for (int i = 0; i < daySchedule.Length; i++)
            {
                daySchedule[i] = new SchedSlot();
            }
        }

        public String Day
        {
            get { return day; }
        }

        public SchedSlot[] DaySchedule
        {
            get { return daySchedule; }
            set { daySchedule = value; }
        }

        public int ScheduleID
        {
            get { return scheduleID; }
            set { scheduleID = value; }
        }
        /*
         * Returned String contains detailed information about the DailySched
         */
        public override String ToString()
        {
            String daySched = "";
            daySched = daySched + day + ":\r\r\n";
            for (int i = 0; i < daySchedule.Length; i++)
            {
                daySched = daySched + daySchedule[i].ToString() + "\r\r\n";
            }
            return daySched;
        }

        /*
         * Returned String contains detailed information about the DailySched
         */
        public String detailedDailySchedForRMTAdmin()
        {
            String daySched = "";
            daySched = daySched + day + ":\r\r\n";
            for (int i = 0; i < daySchedule.Length; i++)
            {
                daySched = daySched + daySchedule[i].detailedSchedForRMTAdmin() + "\r\n";
            }
            return daySched;
        }

        /*
         * Returned String contains detailed information about the DailySched which 
         * corresponds to the rmtName. It only contains partial information about the 
         * DailySched with corresponds to other rmtNames.
         */
        public String detailedDailySchedForRMT(String rmtName)
        {
            String daySched = "";
            daySched = daySched + day + ":\r\n";
            for (int i = 0; i < daySchedule.Length; i++)
            {
                daySched = daySched + daySchedule[i].detailedSchedForRMT(rmtName) + "\r\r\n";
            }
            return daySched;
        }

        /*
         * Returned String contains detailed information about the DailySched which 
         * corresponds to the rmtName. It only contains partial information about the 
         * DailySched with corresponds to other rmtNames.
         */
        public String detailedDailySchedForCustomer(String custName)
        {
            String daySched = "";
            daySched = daySched + day + ":\r\r\n";
            for (int i = 0; i < daySchedule.Length; i++)
            {
                daySched = daySched + daySchedule[i].detailedSchedForCustomer(custName) + "\r\r\n";
            }
            return daySched;
        }


        /*
         * This function reserves SchedSlots for a given RMT 
         * based on the TimeSlot provided (by the RMT)
         * It also calls a method to wrtie the new information about
         * a SchedSlot into the database.
         */
        internal Boolean addRmtSched(Database db, String rmtName, TimeSlot curTS)
        {

            int startIndex = -1, endIndex = -1;
            findSchedSlotIndex(curTS, out startIndex, out endIndex);
            if (startIndex == -1)
            {
                return false;
            }

            if (endIndex == -1)
            {
                return false;
            }

            /*Check to see if the SchedSlots are free(no other RMTs in the slot)*/
            if (isFree(startIndex, endIndex))
            {
                for (int i = startIndex; i < endIndex; i++)
                {
                    if (daySchedule[i] == null)
                    {
                        daySchedule[i] = new SchedSlot();
                    }

                    daySchedule[i].RMT = rmtName;
                    daySchedule[i].writeToDatabse(db);
                }
                return true;
            }
            else
            {
                return false;
            }
        }


        /*
         * This method tries to book an appointment based on the information 
         * taken as parameter.
         * Returns true on success and false otherwise.
         * For more detail please refer to the comments in the body of this method.
         */
        public Boolean bookAppointment(Database db, String rmtName, String custName, String therName,
                                        TimeSlot desiredTS)
        {
            int startIndex = -1, endIndex = -1;
            findSchedSlotIndex(desiredTS, out startIndex, out endIndex);
            bool success = false;

            if (startIndex == -1)
            {
                throw new Exception("The time is not valid: " +
                    desiredTS.StartTime.ToShortTimeString());
            }

            if (endIndex == -1)
            {
                throw new Exception("The time is not valid: " +
                    desiredTS.EndTime.ToShortTimeString());
            }

            /* 
             * Check to see if a 30 minute slot must be considered for preparing the room
             * before the session. 
             * IF the requested booking time is 8am (1st SchedSlot) then no need. (It is 
             * assumed that the room is ready at the begining of the day.)
             */
            if (startIndex == 0)
            {
                if (isFree(startIndex, endIndex, rmtName))
                {
                    for (int i = startIndex; i < endIndex; i++)
                    {
                        this.DaySchedule[i].bookSchedSlot(db, custName, therName);
                    }
                    success = true;
                }
            }

            else
            {
                int prepIndex = startIndex - 1;
                if (isFree(startIndex, endIndex, rmtName))
                {
                    if (isFree(prepIndex, startIndex) || isFree(prepIndex, startIndex, rmtName))//book for preparation first.
                    {
                        DaySchedule[prepIndex].bookSchedSlotForPrep(db, therName);
                        for (int i = startIndex; i < endIndex; i++)
                        {
                            this.DaySchedule[i].bookSchedSlot(db, custName, therName);
                        }
                        success = true;
                    }
                }
            }

            return success;
        }
        

        /*
         * This function reserves SchedSlots for a given RMT 
         * based on the TimeSlot provided (by the RMT)
         * Returns true on success and false otherwise.
         */
        internal bool removeRmtSched(Database db, String rmtName, TimeSlot curTS)
        {

            int startIndex = -1, endIndex = -1;
            findSchedSlotIndex(curTS, out startIndex, out endIndex);
            if (startIndex == -1)
            {
                throw new Exception("The time is not valid: " +
                    curTS.StartTime.ToShortTimeString());
            }

            if (endIndex == -1)
            {
                throw new Exception("The time is not valid: " +
                    curTS.EndTime.ToShortTimeString());
            }

            /*
             * Check to see if the SchedSlots are free(not booked for therapy session
             * or preparation)
             */
            if (isFree(startIndex, endIndex, rmtName))
            {
                for (int i = startIndex; i < endIndex; i++)
                {
                    daySchedule[i].RMT = "";
                    db.removeSchedSlot(DaySchedule[i].ID);
                }
                return true;
            }
            else
            {
                Console.WriteLine("Time slot: " +
                    curTS.StartTime.ToShortTimeString() + " to " +
                    curTS.EndTime.ToShortTimeString() + " for RMT " +
                    rmtName + " is booked.");
                return false;
            }
        }



        /*
         * This method removes the appointment which had been previously set 
         * for the schedslots that corresponds to TimeSlot desiredTS.
         * Returns true on success and false otherwise.
         */
        public Boolean removeAppointment(Database db, TimeSlot desiredTS)
        {
            int startIndex = -1, endIndex = -1;
            findSchedSlotIndex(desiredTS, out startIndex, out endIndex);
            if (startIndex == -1)
            {
                throw new Exception("The time is not valid: " +
                    desiredTS.StartTime.ToShortTimeString());
            }

            if (endIndex == -1)
            {
                throw new Exception("The time is not valid: " +
                    desiredTS.EndTime.ToShortTimeString());
            }

            else if (startIndex == 0)
            {
                for (int i = startIndex; i < endIndex; i++)
                    this.DaySchedule[i].removeAppointment(db);
                return true;
            }
            else
            {
                for (int i = (startIndex - 1); i < endIndex; i++)
                    this.DaySchedule[i].removeAppointment(db);
                return true;
            }
        }

        /*
         * Overloaded method.
         * This method returns true if the shcedslots starting from startIndex and 
         * ending at endIndex in the DaySchedule array:
         * 1)have RMT rmtName in them 
         * 2)are not booked(for therapy session or for preparation)
         * Returns false otherwise.
         */
        private bool isFree(int startIndex, int endIndex, string rmtName)
        {
            Boolean isFree = true;
            for (int i = startIndex; i < endIndex; i++)
            {
                if (this.DaySchedule[i].RMT != rmtName || this.DaySchedule[i].State == 1 ||
                    this.DaySchedule[i].State == 2)
                {
                    isFree = false;
                    break;
                }
            }
            return isFree;
        }

        /*
         * Overloaded method.
         * This method returns true if the shcedslots starting from startIndex and 
         * ending at endIndex in the DaySchedule array:
         * 1)have no RMT working in them
         * 2)are not booked(for preparation)
         * Returns false otherwise.
         */
        private Boolean isFree(int startIndex, int endIndex)
        {
            Boolean isFree = true;
            for (int i = startIndex; i < endIndex; i++)
            {
                if (this.daySchedule[i].RMT != "" || this.DaySchedule[i].State == 2)
                {
                    isFree = false;
                    break;
                }

            }

            return isFree;
        }

        /*
         * This function takes TimeSlot curTS, returns the startIndex 
         * and the endIndex in the [24] SchedSlots
         */
        private static void findSchedSlotIndex(TimeSlot curTS,
            out int startIndex, out int endIndex)
        {

            startIndex = -1;
            endIndex = -1;

            if (curTS.StartTime.Hour < 8 || curTS.StartTime.Hour > 20)
            {
                startIndex = -1;
                endIndex = -1;
            }


            if (curTS.StartTime.Minute == 0)
            {
                startIndex = ((curTS.StartTime.Hour - 8) * 2);
            }

            if (curTS.StartTime.Minute == 30)
            {
                startIndex = ((curTS.StartTime.Hour - 8) * 2) + 1;
            }

            if (curTS.EndTime.Minute == 0)
            {
                endIndex = ((curTS.EndTime.Hour - 8) * 2);
            }

            if (curTS.EndTime.Minute == 30)
            {
                endIndex = ((curTS.EndTime.Hour - 8) * 2) + 1;
            }
        }

    }
}
